package com.tm.car.utils;

import javax.validation.constraints.NotBlank;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * MD5 加密工具类。
 * 该类提供了 MD5 加密功能，支持对字符串和字节数组进行加密，并生成 32 位或 16 位的加密结果。
 * 主要功能包括：
 * 1. 对字符串进行 MD5 加密，返回 32 位大写加密字符串。
 * 2. 对字节数组进行 MD5 加密，返回加密后的字节数组。
 * 3. 对字节数组进行 MD5 加密，返回 32 位加密字符串。
 * <p>
 * 主要组件说明：
 * - `MD5_TABLE`：用于将字节转换为十六进制字符的映射表。
 * - `MessageDigest`：Java 提供的消息摘要工具类，用于实现 MD5 加密算法。
 * <p>
 * 主要方法说明：
 * 1. `getMd5Str(String str)`：对字符串进行 MD5 加密，返回 32 位大写加密字符串。
 * 2. `md5Digest(byte[] bytes)`：对字节数组进行 MD5 加密，返回加密后的字节数组。
 * 3. `md5(byte[] bytes)`：对字节数组进行 MD5 加密，返回 32 位加密字符串。
 * <p>
 * 使用场景：
 * 1. 适用于需要对敏感信息（如密码）进行加密的场景。
 * 2. 支持对字符串或字节数组进行加密，适用于文件校验、数据完整性验证等场景。
 * <p>
 * 注意事项：
 * 1. MD5 是一种不可逆的加密算法，适用于校验和数据摘要，但不适用于高安全性要求的场景。
 * 2. 32 位加密结果是全大写字母形式，16 位加密结果可通过截取 32 位结果的子串实现。
 *
 * @author tnk
 *
 *
 */
public class Md5Util {
    private static final char[] MD5_TABLE = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

    /**
     * md5加密
     */
    public static String getMd5Str(String str) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(str.getBytes());
            byte[] byteDigest = md.digest();
            int i;
            StringBuilder buf = new StringBuilder();
            for (byte element : byteDigest) {
                i = element;
                if (i < 0) {
                    i += 256;
                }
                if (i < 16) {
                    buf.append("0");
                }
                buf.append(Integer.toHexString(i));
            }
            // 32位加密
            return buf.toString().toUpperCase();
            // 16位的加密
            // return buf.toString().substring(8, 24);
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }

    public static byte[] md5Digest(byte[] bytes) {
        MessageDigest m;
        try {
            m = MessageDigest.getInstance("MD5");
            m.update(bytes);
            return m.digest();
        } catch (Exception e) {
            e.printStackTrace(System.err);
        }
        return null;
    }

    public static String md5(byte[] bytes) {
        MessageDigest m;
        try {
            m = MessageDigest.getInstance("MD5");
            m.update(bytes);
            byte[] s = m.digest();
            StringBuilder buf = new StringBuilder(s.length * 2);
            for (byte b : s) {
                buf.append(MD5_TABLE[(b >> 4 & 0xF)]);
                buf.append(MD5_TABLE[(b & 0xF)]);
            }
            return buf.toString();
        } catch (Exception e) {
            e.printStackTrace(System.err);
        }
        return null;
    }

    public static String encode(@NotBlank(message = "密码不能为空") String password) {
        return md5(password.getBytes());
    }
}